using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Diagnostics;
using System.ComponentModel;
using System.Reflection;
using System.Collections;
using System.Windows.Forms;
using THSLib;
using THSERP.BusinessEntities;
namespace THSERP.BaseProvider
{
    public class THSList<T> : List<T>
        where T : BusinessObject, new()
    {
        #region Constant
        public const String cstRelationForeign = "Foreign";
        public const String cstRelationParent = "Parent";
        public const String cstRelationSwitcher = "Switcher";
        
        public const String cstRelationNone = "None";
        #endregion

        #region variables
        protected ERPModuleEntities _entity = new ERPModuleEntities();
        protected String _relation;
        protected String _parentTableName;
        protected String _itemTableName;
        protected THSGridControl _gridControl;
        protected String _itemTableForeignKey;
        protected int _currentIndex;
        protected List<T> _originalList = new List<T>();
        #endregion

        #region Public Properties
        public ERPModuleEntities Entity
        {
            get
            {
                return _entity;
            }
            set
            {
                _entity = value;
            }
        }

        public String Relation
        {
            get
            {
                return _relation;
            }

            set
            {
                _relation = value;
            }
        }

        public THSGridControl GridControl
        {
            get
            {
                return _gridControl;
            }
            set
            {
                _gridControl = value;
            }
        }

        public DevExpress.XtraGrid.Views.Grid.GridView GridView
        {
            get
            {
                return (DevExpress.XtraGrid.Views.Grid.GridView)GridControl.Views[0];
            }
        }

        public String ParentTableName
        {
            get
            {
                return _parentTableName;
            }
            set
            {
                _parentTableName = value;
            }
        }

        public String ItemTableName
        {
            get
            {
                return _itemTableName;
            }

            set
            {
                _itemTableName = value;
            }
        }

        public String ItemTableForeignKey
        {
            get
            {
                return _itemTableForeignKey;
            }
            set
            {
                _itemTableForeignKey = value;
            }
        }

        public int CurrentIndex
        {
            get
            {
                if (GridControl != null)
                    return GridView.GetDataSourceRowIndex(GridView.FocusedRowHandle);
                return -1;
            }
        }

        public List<T> OriginalList
        {
            get
            {
                return _originalList;
            }
            set
            {
                _originalList = value;
            }
        }
        #endregion

        #region Constructor
        public THSList()
        {

        }

        public THSList(ERPModuleEntities entity, String strParentTaleName, String strItemTableName)
        {
            InitTHSList(entity, strParentTaleName, strItemTableName);
        }
        #endregion

        #region Init
        public void InitTHSList(ERPModuleEntities ent, String strParentTableName, String strItemTableName)
        {
            Entity = ent;
           
            ParentTableName = strParentTableName;
            ItemTableName = strItemTableName;
            
            if (!String.IsNullOrEmpty(ParentTableName))
            {
                
                String strParentTablePrimaryColumn = THSDbUtil.GetTablePrimaryColumn(ParentTableName);
                String strItemTablePrimaryColumn = THSDbUtil.GetTablePrimaryColumn(ItemTableName);
                ItemTableForeignKey = "FK_" + strParentTablePrimaryColumn;
                if (THSDbUtil.ColumnIsExist(ItemTableName, ItemTableForeignKey))
                    Relation = cstRelationForeign;
                else
                {
                    ItemTableForeignKey = "FK_" + strItemTablePrimaryColumn.Substring(0, strItemTablePrimaryColumn.Length - 2) + "ParentID";
                    if (THSDbUtil.ColumnIsExist(ItemTableName, ItemTableForeignKey))
                        Relation = cstRelationForeign;
                    else if (ItemTableName.Equals(ParentTableName))
                    {
                        Relation = cstRelationParent;
                        ItemTableForeignKey = ItemTableName.Substring(0, ItemTableName.Length - 1) + "ParentID";
                    }
                    else
                        Relation = cstRelationSwitcher;
                }
            }
            else
            {
                Relation = cstRelationNone;
            }
        }

        /// <summary>
        /// Init THS list with given relation
        /// </summary>
        ///
        public void InitTHSList(ERPModuleEntities ent, String strParentTableName, String strItemTableName, String strRelation)
        {
            Entity = ent;
           
            ParentTableName = strParentTableName;
            ItemTableName = strItemTableName;
            Relation = strRelation;
            switch (strRelation)
            {
                case cstRelationForeign:
                    {
                        String strParentTablePrimaryColumn = THSDbUtil.GetTablePrimaryColumn(ParentTableName);
                        String strItemTablePrimaryColumn = THSDbUtil.GetTablePrimaryColumn(ItemTableName);
                        ItemTableForeignKey = "FK_" + strParentTablePrimaryColumn;
                        if (!THSDbUtil.ColumnIsExist(ItemTableName, ItemTableForeignKey))
                            ItemTableForeignKey = "FK_" + strItemTablePrimaryColumn.Substring(0, strItemTablePrimaryColumn.Length - 2) + "ParentID";
                        break;
                    }
                case cstRelationParent:
                    {
                        ItemTableForeignKey =  ItemTableName.Substring(0, ItemTableName.Length - 1) + "ParentID";
                        break;
                    }
            }
        }

        public virtual void InitTHSListGridControl()
        {
            String strGridControlName = "fld_dgc" + ItemTableName;
            InitTHSListGridControl(strGridControlName);
        }

       
        public virtual void InitTHSListGridControl(String strGridControlName)
        {
            if (Entity.Module.Controls[strGridControlName] != null)
            {
                this.GridControl = (THSGridControl)Entity.Module.Controls[strGridControlName];
                DevExpress.XtraGrid.Views.Grid.GridView gridView = (DevExpress.XtraGrid.Views.Grid.GridView)this.GridControl.Views[0];
                gridView.FocusedRowChanged += new DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventHandler(GridView_FocusedRowChanged);
                //hieu.nguyen remove 10/08/2011 reason excute 2 times key up on gridcontrol
                //gridView.KeyUp += new KeyEventHandler(GridView_KeyUp);
                gridView.CellValueChanging += new DevExpress.XtraGrid.Views.Base.CellValueChangedEventHandler(GridView_CellValueChanging);
                gridView.InitNewRow += new DevExpress.XtraGrid.Views.Grid.InitNewRowEventHandler(GridView_InitNewRow);
            }
        }

        public void SetDefaultListAndRefreshGridControl()
        {
            this.Clear();
            this.OriginalList.Clear();
            if (GridControl != null)
            {
                if (Entity.Module.Controls[GridControl.Name] != null)
                {
                    (Entity.Module.Controls[GridControl.Name] as THSGridControl).RefreshDataSource();
                }
            }
        }
        #endregion

        #region Invalidate
        public virtual void Invalidate(int iObjectID)
        {
            
            if (GridControl != null)
                GridControl.InvalidateLookupEditColumns();

           
            BaseBusinessController objItemController = BusinessControllerFactory.GetBusinessController(ItemTableName + "Controller");
            DataSet ds = new DataSet();

            if (Relation.Equals(cstRelationForeign))
            {
                ds = objItemController.GetAllDataByForeignColumn(ItemTableForeignKey, iObjectID);

            }
            else if (Relation.Equals(cstRelationParent))
            {
                ds = objItemController.GetAllObjectsByObjectParentID(iObjectID);
            }
        
            else if (Relation.Equals(cstRelationNone))
            {
                ds = objItemController.GetAllObjects();
            }

            Invalidate(ds);
        }
        //
        public virtual void Invalidate(int iObjectID,bool IsTree)
        {

            if (GridControl != null)
                GridControl.InvalidateLookupEditColumns();


            BaseBusinessController objItemController = BusinessControllerFactory.GetBusinessController(ItemTableName + "Controller");
            DataSet ds = new DataSet();

            if (Relation.Equals(cstRelationForeign))
            {
                ds = objItemController.GetAllDataByForeignColumn(ItemTableForeignKey, iObjectID);

            }
            else if (Relation.Equals(cstRelationParent))
            {
                ds = objItemController.GetAllObjectsByObjectParentID(iObjectID);
            }

            else if (Relation.Equals(cstRelationNone))
            {
                ds = objItemController.GetAllObjects();
            }

            Invalidate(ds);
        }

        public virtual void Invalidate(DataSet ds)
        {
            this.Clear();

            BaseBusinessController objItemController = BusinessControllerFactory.GetBusinessController(ItemTableName + "Controller");

            if (ds.Tables.Count > 0)
            {
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    T objT = (T)objItemController.GetObjectFromDataRow(row);
                    this.Add(objT);
                }
            }

            //Invalidate original list same as itself
            OriginalList.Clear();
            foreach (T obj in this)
                OriginalList.Add((T)obj.Clone());

           
            if (GridControl != null)
            {
                GridControl.RefreshDataSource();

                if (this.Count > 0)
                    GridViewFocusRow(0);
                else
                    Entity.InvalidateModuleObject(BusinessObjectFactory.GetBusinessObject(ItemTableName + "Info"));
            }
        }

        
        public virtual void Invalidate(List<T> lst)
        {
            this.Clear();
            foreach (T obj in lst)
            {
                this.Add((T)obj.Clone());
            }

            //Invalidate original list same as itself
            OriginalList.Clear();
            foreach (T obj in this)
                OriginalList.Add((T)obj.Clone());

            if (GridControl != null)
            {
                GridControl.RefreshDataSource();

                if (this.Count > 0)
                    GridViewFocusRow(0);
                else
                    Entity.InvalidateModuleObject(BusinessObjectFactory.GetBusinessObject(ItemTableName + "Info"));
            }
        }
        #endregion

        #region Save List
        public virtual T SaveObjectToList(bool IsNew)
        {
            //Invalidate look up edit columns
            if (GridControl != null)
                GridControl.InvalidateLookupEditColumns();

           
            String strMainTableName = String.Empty;
            if(Entity.MainObject!=null)
                strMainTableName = THSUtil.GetTableNameFromBusinessObject(Entity.MainObject);

            T objT = new T();
            if (!String.IsNullOrEmpty(ParentTableName))
            {
                if (ItemTableName.Equals(strMainTableName))
                {
                    objT = (T)Entity.MainObject.Clone();
                }
                else
                {
                    objT = (T)Entity.ModuleObjects[ItemTableName].Clone();
                }
            }
            else
            {
                objT = (T)Entity.ModuleObjects[ItemTableName].Clone();
            }

            if (IsNew)
            {
                String strPrimaryKey = ItemTableName.Substring(0, ItemTableName.Length - 1) + "ID";
                THSDbUtil.SetPropertyValue(objT, strPrimaryKey, 0);
                this.Add(objT);
            }
            else
            {
                if (CurrentIndex >= 0)
                    this[CurrentIndex] = objT;
            }
            return objT;
        }

        public virtual void AddObjectToList()
        {
            this.SaveObjectToList(true);
            GridControl.RefreshDataSource();
            GridViewFocusRow(this.Count - 1);
        }

        public virtual void ChangeObjectFromList()
        {
            this.SaveObjectToList(false);
            GridControl.RefreshDataSource();
            GridViewFocusRow(GridView.FocusedRowHandle);
        }
      
        public virtual void RemoveObjectFromList(int iIndex)
        {
            if (this.Count > iIndex)
            {
                this.RemoveAt(iIndex);
            }

            GridControl.RefreshDataSource();
            if (this.Count > 0)
            {
                if (this.Count > GridView.FocusedRowHandle)
                    GridViewFocusRow(GridView.FocusedRowHandle);
                else
                    GridViewFocusRow(this.Count - 1);
            }
            else
                Entity.InvalidateModuleObject(BusinessObjectFactory.GetBusinessObject(ItemTableName + "Info"));

            //Do something after removing item object
            Entity.DoActionAfterRemovingItemObject(ItemTableName);
        }

        public virtual void RemoveSelectedRowObjectFromList()
        {
            if (GridView.FocusedRowHandle >= 0)
                RemoveObjectFromList(CurrentIndex);
        }

        public virtual bool Exists(String strPropertyName, object objPropertyValue)
        {
            if (this.PosOf(strPropertyName, objPropertyValue) >= 0)
                return true;
            return false;
        }

        public virtual void GridViewFocusRow(int iRowHandle)
        {
            GridView.FocusedRowHandle = iRowHandle;
            if (CurrentIndex >= 0)
                Entity.InvalidateModuleObject((T)this[CurrentIndex].Clone());
        }

        #endregion

        #region Save List, Delete List to database
        public virtual void DeleteAllItemObjects()
        {
            try
            {
               
                BaseBusinessController objItemsController = BusinessControllerFactory.GetBusinessController(ItemTableName + "Controller");
                switch (Relation)
                {
                    case cstRelationSwitcher:
                        {
                            int iParentObjectID = GetParentObjectID();
                            if (iParentObjectID > 0)
                            {
                                String strSwitcherTableName = ParentTableName.Substring(0, ParentTableName.Length - 1) + ItemTableName.Substring(2);
                                objItemsController.DeleteFromOwner(ParentTableName, iParentObjectID, strSwitcherTableName);
                            }
                            
                            break;
                        }
                    case cstRelationForeign:
                        {
                            int iParentObjectID = GetParentObjectID();
                            if (iParentObjectID > 0)
                            {
                                objItemsController.DeleteByForeignColumn(ItemTableForeignKey, iParentObjectID);
                            }                            
                            break;
                        }


                    case cstRelationParent:
                        {
                            break;
                        }

                    case cstRelationNone:
                        {
                            objItemsController.DeleteAllObjects();
                            break;
                        }

                    default:
                        {
                            MessageBox.Show("THSList.DeleteItemObjects function:Relation invalid", "Bug");
                            return;
                        }
                }

                
            }
            catch (Exception ex)
            {
                MessageBox.Show("Bug: THSList.DeleteItemsObject-" + ex.Message, "Bug");
            }
        }

        
        public virtual void DeleteItemObjects()
        {
           
            BaseBusinessController objItemsController = BusinessControllerFactory.GetBusinessController(ItemTableName + "Controller");
            String strPrimaryColumn = THSDbUtil.GetTablePrimaryColumn(ItemTableName);

            foreach (T obj in this)
            {
                int iObjectID = Convert.ToInt32(THSDbUtil.GetPropertyValue(obj, strPrimaryColumn));
                objItemsController.DeleteObject(iObjectID);
            }
        }

        
        public virtual void SaveItemObjects()
        {
            try
            {
                EndCurrentEdit();

               
                String strItemTablePrimaryKey = THSDbUtil.GetTablePrimaryColumn(ItemTableName); 
                BaseBusinessController objItemsController = BusinessControllerFactory.GetBusinessController(ItemTableName + "Controller");

                foreach (T objT in this)
                {
                    int iItemObjectID = (int)THSDbUtil.GetPropertyValue(objT, strItemTablePrimaryKey);
                    switch (Relation)
                    {
                        case cstRelationSwitcher:
                            {
                                break;
                            }
                        case cstRelationForeign:
                            {
                                int iParentObjectID = GetParentObjectID();
                                if (iParentObjectID > 0)
                                {
                                    if (THSDbUtil.GetPropertyValue(objT, ItemTableForeignKey) != null)
                                        THSDbUtil.SetPropertyValue(objT, ItemTableForeignKey, iParentObjectID);
                                }
                                break;
                            }
                        case cstRelationParent:
                            {
                                break;
                            }
                        case cstRelationNone:
                            {
                                break;
                            }
                    }

                    //Create or update items
                    if (iItemObjectID > 0)
                    {
                        THSDbUtil.SetPropertyValue(objT, ERPModuleEntities.AAUpdatedUser, THSApp.CurrentUser);
                        THSDbUtil.SetPropertyValue(objT, ERPModuleEntities.AAUpdatedDate, DateTime.Now);
                        objItemsController.UpdateObject(objT);
                    }
                    else
                    {
                        THSDbUtil.SetPropertyValue(objT, ERPModuleEntities.AACreatedUser, THSApp.CurrentUser);
                        THSDbUtil.SetPropertyValue(objT, ERPModuleEntities.AACreatedDate, DateTime.Now);
                        objItemsController.CreateObject(objT);
                    }
                }

                //Delete items
                foreach (T obj in OriginalList)
                {
                    int iItemObjectID = (int)THSDbUtil.GetPropertyValue(obj, strItemTablePrimaryKey);
                    if (iItemObjectID > 0 && !this.Exists(strItemTablePrimaryKey, iItemObjectID))
                    {
                        objItemsController.DeleteObject(iItemObjectID);
                        Entity.DeleteObjectRelations(ItemTableName, iItemObjectID);
                    }
                }
                //Invalidate original list
                OriginalList.Clear();
                foreach (T obj in this)
                    OriginalList.Add((T)obj.Clone());
            }
            catch (Exception e)
            {
                MessageBox.Show("THSList.SaveItemObjects -" + e.Message, "Bug");
            }
        }

        
        public virtual void SaveItemObjects(bool bDeleteFirst)
        {
           
            if (bDeleteFirst)
            {
                DeleteAllItemObjects();
            }

            SaveItemObjects();
        }
        #endregion

        #region GridControl,GridView event handlers
        protected virtual void GridView_FocusedRowChanged(object sender, DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs e)
        {
            DevExpress.XtraGrid.Views.Grid.GridView gridView = (DevExpress.XtraGrid.Views.Grid.GridView)GridControl.Views[0];
            if (this.Count > 0)
                if (CurrentIndex >= 0)
                {
                    String strMainTableName = String.Empty;
                    if(Entity.MainObject!=null)
                        strMainTableName=THSUtil.GetTableNameFromBusinessObject(Entity.MainObject);

                    if (ItemTableName.Equals(strMainTableName))
                    {
                        Entity.MainObject = (BusinessObject)this[CurrentIndex].Clone();
                        Entity.UpdateMainObjectBindingSource();
                    }
                    else
                        Entity.InvalidateModuleObject((T)this[CurrentIndex].Clone());
                }

        }
        //hieu.nguyen remove 10/08/2011 reason excute 2 times key up on gridcontrol
        //protected virtual void GridView_KeyUp(object sender, KeyEventArgs e)
        //{
        //    if (this.Count > 0)
        //    {
        //        if (e.KeyCode == Keys.Delete)
        //            if (CurrentIndex >= 0)
        //            {
        //                RemoveSelectedRowObjectFromList();
        //            }
        //    }
        //}

        protected virtual void GridView_CellValueChanging(object sender, DevExpress.XtraGrid.Views.Base.CellValueChangedEventArgs e)
        {
            if (Entity.Module.Toolbar.IsNullOrNoneAction())
            {
                if (Entity.ModuleObjects[ItemTableName] != null && Entity.ModuleObjects[ItemTableName].AllowPropertyChangedEvent)
                    Entity.Module.ActionEdit();
            }
        }

        protected virtual void GridView_InitNewRow(object sender, DevExpress.XtraGrid.Views.Grid.InitNewRowEventArgs e)
        {
            if (Entity.Module.Toolbar.IsNullOrNoneAction())
            {
                if (Entity.ModuleObjects[ItemTableName] != null && Entity.ModuleObjects[ItemTableName].AllowPropertyChangedEvent)
                    Entity.Module.ActionEdit();
            }
        }
        #endregion

        //Get position of object in list
        public virtual int PosOf(String strPropertyName, object objPropertyValue)
        {
           
            for (int i = 0; i < this.Count; i++)
            {
                object objValue = THSDbUtil.GetPropertyValue((T)this[i], strPropertyName);
                if (objPropertyValue.Equals(objValue))
                    return i;
            }
            return -1;
        }

        
        public int GetParentObjectID()
        {
           
            String strMainTableName = String.Empty;
            if (Entity.MainObject != null)
                strMainTableName = THSUtil.GetTableNameFromBusinessObject(Entity.MainObject);
            String strParentTablePrimaryKey = String.Empty;
            if (!String.IsNullOrEmpty(ParentTableName))
                strParentTablePrimaryKey = THSDbUtil.GetTablePrimaryColumn(ParentTableName);
            int iParentObjectID = 0;
            if (!String.IsNullOrEmpty(ParentTableName))
            {
                if (ParentTableName == strMainTableName)
                    iParentObjectID = (int)THSDbUtil.GetPropertyValue(Entity.MainObject, strParentTablePrimaryKey);
            }
            return iParentObjectID;
        }

        /// <summary>
        /// Duplicate list by setting all item primary key to zero
        /// </summary>
        /// 
        public virtual void Duplicate()
        {
            OriginalList.Clear();
           
            String itemTablePrimaryColumn = THSDbUtil.GetTablePrimaryColumn(ItemTableName);
            foreach (T obj in this)
                THSDbUtil.SetPropertyValue(obj, itemTablePrimaryColumn, 0);
        }

        /// <summary>
        /// End current edit to update binding list
        /// </summary>
        /// 
        public virtual void EndCurrentEdit()
        {
            if (GridControl != null)
                GridView.FocusedRowHandle = -1;
        }

        /// <summary>
        /// Count the number of appearance of object by property name and value
        /// </summary>
        ///
        public virtual int GetFrequence(String strPropertyName, object objPropertyValue)
        {
           
            int count = 0;
            for (int i = 0; i < this.Count; i++)
            {
                object objValue = THSDbUtil.GetPropertyValue((T)this[i], strPropertyName);
                if (objPropertyValue.Equals(objValue))
                    count++;
            }
            return count;
        }
    }
}
